package community.hospital.aspect;

import community.hospital.annotation.EnableOperationLog;
import community.hospital.annotation.Module;
import community.hospital.annotation.Log;
import community.hospital.common.LoginUserHolder;
import community.hospital.entity.OperationLog;
import community.hospital.entity.response.UserResponse;
import community.hospital.service.domain.OperationLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import java.util.Map;

import static community.hospital.common.Constant.UNKNOWN_MODULE;

/**
 * @Author：ydj
 * @Date：2023/2/4 19:05
 */
@Aspect
//@Component
@Slf4j
@Order(4)
public class OperationLogAspect  implements ApplicationContextAware{
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Resource
    private OperationLogService operationLogService;

    private ApplicationContext applicationContext;
    @Around("@annotation(log)")
    public Object operationLogAspect(ProceedingJoinPoint pjp, Log log) {
        Map<String, Object> map = applicationContext.getBeansWithAnnotation(EnableOperationLog.class);

        Object result = null;
        HttpServletRequest request = (HttpServletRequest) RequestContextHolder.getRequestAttributes().resolveReference(RequestAttributes.REFERENCE_REQUEST);
        String requestURI = request.getRequestURI();
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Module module = (Module) methodSignature.getDeclaringType().getAnnotation(Module.class);
        String moduleName = "";
        moduleName =module != null? module.value():UNKNOWN_MODULE;
        String methodName = log.methodName();
        String desc = log.desc();
        UserResponse user = LoginUserHolder.getUser();
        OperationLog operationLog = new OperationLog()
                .setModuleName(moduleName)
                .setMethodName(methodName)
                .setDescription(desc)
                .setRequestUrl(requestURI)
                .setState(0);
        operationLog.setUserId(user != null?user.getId():null);
        try {
            result = pjp.proceed();
        } catch (Throwable e) {
            operationLog.setState(1);
            e.printStackTrace();
        } finally {
            threadPoolTaskExecutor.execute(()->{
                operationLogService.save(operationLog);
            });
        }
        return result;
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


}
